package com.rn_demo3.rnFile;

import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.net.Uri;
import android.provider.DocumentsContract;
import android.util.Log;

import com.facebook.react.bridge.ActivityEventListener;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.rn_demo3.util.Crypt;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

public class RNFileModule extends ReactContextBaseJavaModule {
    private static final int PICKFILE_REQUEST_CODE = 369;
    private ReactApplicationContext mContext;
    public static final String LOG_TAG = "RNFileModule";
    private final ActivityEventListener mActivityEventListener = new ActivityEventListener() {
        @Override
        public void onActivityResult(Activity activity, int requestCode, int resultCode, @Nullable Intent intent) {

            if(requestCode == PICKFILE_REQUEST_CODE && resultCode == Activity.RESULT_OK){
                Uri uri = null;
                if(intent != null){
                    uri = intent.getData();

                }
            }
        }

        @Override
        public void onNewIntent(Intent intent) {

        }
    };

    public RNFileModule(ReactApplicationContext reactContext) {
        super(reactContext);
        mContext = reactContext;
        reactContext.addActivityEventListener(mActivityEventListener);
    }

    @NonNull
    @Override
    public String getName() {
        return "RNFileModule";
    }

    @ReactMethod
    public void openFile(){
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("*/*");

        intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, true);

        getCurrentActivity().startActivityForResult(intent, PICKFILE_REQUEST_CODE);
    }

    @ReactMethod
    public void openAssignFolder(String path){
        File file = new File(path);
        if(null==file || !file.exists()){
            return;
        }
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setDataAndType(Uri.fromFile(file), "file/*");
        try {
//            mContext.startActivity(intent);
            mContext.startActivity(Intent.createChooser(intent,"选择浏览工具"));
        } catch (ActivityNotFoundException e) {
            e.printStackTrace();
        }
    }



    @ReactMethod
    public void readFile(String filepath, Promise promise) {

        StringBuilder content = new StringBuilder();
        try {
            BufferedReader br = new BufferedReader(new FileReader(filepath));
            String line;

            while ((line = br.readLine()) != null) {
                if(line.contains(",")){
                    content.append(line.trim());
                    content.append("\n");
                }
            }
            promise.resolve(content.toString());
        } catch (IOException ex) {
            promise.reject(null,  ex.getMessage());
        }

        /*
        try {
            InputStream inputStream = getInputStream(filepath);
            byte[] inputData = getInputStreamBytes(inputStream);
            WritableArray byteArray = bytesToWritableArray(inputData);
            String hexString = ConvertUtil.formatHex2String(inputData);

            WritableMap map = Arguments.createMap();
            map.putString("hex",hexString);
            map.putArray("bytes",byteArray);
            promise.resolve(map);
        } catch (Exception ex) {
            ex.printStackTrace();
            promise.reject(null,  ex.getMessage());
        }
        */
    }

    @ReactMethod
    public void decodeFile(String filepath,String finalPath,String pwd, Promise promise) {
        try {
            Log.d(LOG_TAG,"pwd:" + pwd);
            Crypt crypt = new Crypt(mContext,pwd);
            File file1 = new File(filepath);
            File file2 = new File(finalPath);
            boolean isSuccess = crypt.fileDe(file1,file2);
            Log.d(LOG_TAG,"decode res:" + isSuccess);

            if(isSuccess){
                WritableMap map = Arguments.createMap();
//            map.putArray("bytes",bytesToWritableArray(finalBytes));
                map.putBoolean("isSuccess",isSuccess);
                promise.resolve(map);
            }else{
                promise.resolve(null);
            }

        } catch (Exception ex) {
            ex.printStackTrace();
            promise.reject(null,  ex.getMessage());
        }
    }

    @ReactMethod
    public void writeByteToFile(String filepath, ReadableArray message, Promise promise) {
        Log.d(LOG_TAG, "hexString: " + message);
        try {

            byte[] decoded = new byte[message.size()];

            for (int i = 0; i < message.size(); i++) {
                decoded[i] = new Integer(message.getInt(i)).byteValue();
            }
            Log.d(LOG_TAG, "Message(" + decoded.length + "): " + bytesToHex(decoded));
            OutputStream outputStream = getOutputStream(filepath, false);
            outputStream.write(decoded);
            outputStream.close();

            promise.resolve(null);
        } catch (Exception ex) {
            ex.printStackTrace();
            reject(promise, filepath, ex);
        }
    }

    private OutputStream getOutputStream(String filepath, boolean append) throws IORejectionException {
        Uri uri = getFileUri(filepath, false);
        OutputStream stream;
        try {
            stream = mContext.getContentResolver().openOutputStream(uri, append ? "wa" : getWriteAccessByAPILevel());
        } catch (FileNotFoundException ex) {
            throw new IORejectionException("ENOENT", "ENOENT: " + ex.getMessage() + ", open '" + filepath + "'");
        }
        if (stream == null) {
            throw new IORejectionException("ENOENT", "ENOENT: could not open an output stream for '" + filepath + "'");
        }
        return stream;
    }

    private void reject(Promise promise, String filepath, Exception ex) {
        if (ex instanceof FileNotFoundException) {
            rejectFileNotFound(promise, filepath);
            return;
        }
        if (ex instanceof IORejectionException) {
            IORejectionException ioRejectionException = (IORejectionException) ex;
            promise.reject(ioRejectionException.getCode(), ioRejectionException.getMessage());
            return;
        }

        promise.reject(null, ex.getMessage());
    }
    private void rejectFileNotFound(Promise promise, String filepath) {
        promise.reject("ENOENT", "ENOENT: no such file or directory, open '" + filepath + "'");
    }
    private InputStream getInputStream(String filepath) throws IORejectionException {
        Uri uri = getFileUri(filepath, false);
        InputStream stream;
        try {
            stream = mContext.getContentResolver().openInputStream(uri);
        } catch (FileNotFoundException ex) {
            throw new IORejectionException("ENOENT", "ENOENT: " + ex.getMessage() + ", open '" + filepath + "'");
        }
        if (stream == null) {
            throw new IORejectionException("ENOENT", "ENOENT: could not open an input stream for '" + filepath + "'");
        }
        return stream;
    }


    private static byte[] getInputStreamBytes(InputStream inputStream) throws IOException {
        byte[] bytesResult;
        ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
        int bufferSize = 1024;
        byte[] buffer = new byte[bufferSize];
        try {
            int len;
            while ((len = inputStream.read(buffer)) != -1) {
                byteBuffer.write(buffer, 0, len);
            }
            bytesResult = byteBuffer.toByteArray();
        } finally {
            try {
                byteBuffer.close();
            } catch (IOException ignored) {
            }
        }
        return bytesResult;
    }

    private Uri getFileUri(String filepath, boolean isDirectoryAllowed) throws IORejectionException {
        Uri uri = Uri.parse(filepath);
        if (uri.getScheme() == null) {
            // No prefix, assuming that provided path is absolute path to file
            File file = new File(filepath);
            if (!isDirectoryAllowed && file.isDirectory()) {
                throw new IORejectionException("EISDIR", "EISDIR: illegal operation on a directory, read '" + filepath + "'");
            }
            uri = Uri.parse("file://" + filepath);
        }
        return uri;
    }

    private String getWriteAccessByAPILevel() {
        return android.os.Build.VERSION.SDK_INT <= android.os.Build.VERSION_CODES.P ? "w" : "rwt";
    }

    private final static char[] hexArray = "0123456789ABCDEF".toCharArray();

    public static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for (int j = 0; j < bytes.length; j++) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }

    public static WritableArray bytesToWritableArray(byte[] bytes) {
        WritableArray value = Arguments.createArray();
        for (int i = 0; i < bytes.length; i++)
            value.pushInt((bytes[i] & 0xFF));
        return value;
    }
}



